# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)

# Standard library imports
import os
import os.path as osp
import mimetypes as mime
import sys

# Third party imports
from qtpy.QtCore import QBuffer, QByteArray
from qtpy.QtGui import QColor, QIcon, QImage, QPainter, QPixmap
from qtpy.QtWidgets import QStyle, QWidget

# Local imports
from spyder.config.manager import CONF
from spyder.config.utils import EDIT_EXTENSIONS
from spyder.utils.image_path_manager import get_image_path
from spyder.utils.palette import SpyderPalette
from spyder.utils.svg_colorizer import SVGColorize
import qtawesome as qta

class IconManager():
    """Class that manages all the icons."""
    def __init__(self):
        self.MAIN_FG_COLOR = SpyderPalette.ICON_1
        self.BIN_FILES = {x: 'ArchiveFileIcon' for x in [
            'zip', 'x-tar', 'x-7z-compressed', 'rar']}

        self.DOCUMENT_FILES = {
            'vnd.ms-powerpoint': 'PowerpointFileIcon',
            'vnd.openxmlformats-officedocument.'
            'presentationml.presentation': 'PowerpointFileIcon',
            'msword': 'WordFileIcon',
            'vnd.openxmlformats-officedocument.'
            'wordprocessingml.document': 'WordFileIcon',
            'vnd.ms-excel': 'ExcelFileIcon',
            'vnd.openxmlformats-officedocument.'
            'spreadsheetml.sheet': 'ExcelFileIcon',
            'pdf': 'PDFIcon'}

        self.OFFICE_FILES = {
            '.xlsx': 'ExcelFileIcon',
            '.docx': 'WordFileIcon',
            '.pptx': 'PowerpointFileIcon'}

        self.ICONS_BY_EXTENSION = {}

        # Magnification factors for attribute icons per platform
        if sys.platform.startswith('linux'):
            self.BIG_ATTR_FACTOR = 1.0
            self.SMALL_ATTR_FACTOR = 0.9
        elif os.name == 'nt':
            self.BIG_ATTR_FACTOR = 1.1
            self.SMALL_ATTR_FACTOR = 1.0
        else:
            self.BIG_ATTR_FACTOR = 1.3
            self.SMALL_ATTR_FACTOR = 1.1

        # Icons for different programming language
        # extensions
        self.LANGUAGE_ICONS = {
            '.c': 'CFileIcon',
            '.h': 'CFileIcon',
            '.cc': 'CppFileIcon',
            '.hh': 'CppFileIcon',
            '.cpp': 'CppFileIcon',
            '.cxx': 'CppFileIcon',
            '.c++': 'CppFileIcon',
            '.hpp': 'CppFileIcon',
            '.hxx': 'CppFileIcon',
            '.h++': 'CppFileIcon',
            '.cs': 'CsharpFileIcon',
            '.asmx': 'CsharpFileIcon',
            '.py': 'PythonFileIcon',
            '.py3': 'PythonFileIcon',
            '.pyx': 'PythonFileIcon',
            '.pyw': 'PythonFileIcon',
            '.java': 'JavaFileIcon',
            '.jav': 'JavaFileIcon',
            '.j': 'JavaFileIcon',
            '.js': 'JavascriptFileIcon',
            '.r': 'RFileIcon',
            '.rnw': 'RFileIcon',
            '.rmd': 'RFileIcon',
            '.swift': 'SwiftFileIcon',
            '.csv': 'GridFileIcon',
            '.tsv': 'GridFileIcon',
            '.bat': 'WindowsFileIcon',
            '.psl': 'PowershellFileIcon',
            '.sh': 'DollarFileIcon',
            '.md': 'MarkdownFileIcon',
            '.json': 'JsonFileIcon',
            '.html': 'CodeFileIcon',
            '.css': 'CodeFileIcon',
            '.yml': 'ExclamationFileIcon',
            '.yaml': 'ExclamationFileIcon',
            '.xml': 'CodeFileIcon'
        }

        self._resource = {
            'directory': osp.join(
                osp.dirname(osp.realpath(__file__)), '../fonts'),
            'loaded': False,
        }

        self.ICON_COLORS = {
            'ICON_1':            SpyderPalette.ICON_1,
            'ICON_2':            SpyderPalette.ICON_2,
            'ICON_3':            SpyderPalette.ICON_3,
            'ICON_4':            SpyderPalette.ICON_4,
            'ICON_5':            SpyderPalette.ICON_5,
            'ICON_6':            SpyderPalette.ICON_6,
            'ICON_7':            SpyderPalette.ICON_7,
            'SPYDER_LOGO_WEB':   SpyderPalette.SPYDER_LOGO_WEB,
            'SPYDER_LOGO_SNAKE': SpyderPalette.SPYDER_LOGO_SNAKE,
            # Connection status colors
            'active':            SpyderPalette.COLOR_SUCCESS_3,
            'inactive':          SpyderPalette.COLOR_OCCURRENCE_5,
            'error':             SpyderPalette.COLOR_ERROR_2,
            'connecting':        SpyderPalette.COLOR_WARN_4,
        }

        # Cache for processed icons
        self._icon_cache = {}

        self._qtaargs = {
            'environment':             [('mdi.cube-outline',), {'color': self.MAIN_FG_COLOR}],
            'drag_dock_widget':        [('mdi.drag-variant',), {'color': self.MAIN_FG_COLOR}],
            'format_letter_case':      [('mdi.format-letter-case',), {'color': self.MAIN_FG_COLOR}],
            'format_letter_matches':   [('mdi.format-letter-matches',), {'color': self.MAIN_FG_COLOR}],
            'no_matches':              [('mdi.do-not-disturb',), {'color': SpyderPalette.COLOR_WARN_2}],
            'clear_text':              [('mdi.backspace',), {'color': self.MAIN_FG_COLOR}],
            'regex':                   [('mdi.regex',), {'color': self.MAIN_FG_COLOR}],
            'log':                     [('mdi.file-document',), {'color': self.MAIN_FG_COLOR}],
            'configure':               [('mdi.wrench',), {'color': self.MAIN_FG_COLOR, 'rotated': 90}],
            'bold':                    [('mdi.format-bold',), {'color': self.MAIN_FG_COLOR}],
            'italic':                  [('mdi.format-italic',), {'color': self.MAIN_FG_COLOR}],
            'run_small':               [('mdi.play',), {'color': SpyderPalette.ICON_3}],
            'stop':                    [('mdi.stop',), {'color': SpyderPalette.COLOR_ERROR_1}],
            'keyboard':                [('mdi.keyboard',), {'color': self.MAIN_FG_COLOR}],
            'eyedropper':              [('mdi.eyedropper',), {'color': self.MAIN_FG_COLOR}],
            'tooloptions':             [('mdi.menu',), {'color': self.MAIN_FG_COLOR}],
            'filenew':                 [('mdi.file',), {'color': self.MAIN_FG_COLOR}],
            'fileopen':                [('mdi.folder-open',), {'color': self.MAIN_FG_COLOR}],
            'revert':                  [('mdi.undo',), {'color': self.MAIN_FG_COLOR}],
            'filesave':                [('mdi.content-save',), {'color': self.MAIN_FG_COLOR}],
            'save_all':                [('mdi.content-save-all',), {'color': self.MAIN_FG_COLOR}],
            'filesaveas':              [('mdi.content-save-edit',), {'color': self.MAIN_FG_COLOR}],
            'print':                   [('mdi.printer',), {'color': self.MAIN_FG_COLOR}],
            'fileclose':               [('mdi.close',), {'color': self.MAIN_FG_COLOR}],
            'breakpoint_transparent':  [('mdi.checkbox-blank-circle',), {'color': SpyderPalette.COLOR_ERROR_1, 'opacity': 0.75, 'scale_factor': 0.9}],
            'breakpoint_big':          [('mdi.checkbox-blank-circle',), {'color': SpyderPalette.ICON_4, 'scale_factor': 0.9} ],
            'breakpoint_cond_big':     [('mdi.help-circle',), {'color': SpyderPalette.ICON_4, 'scale_factor': 0.9},],
            'breakpoints':             [('mdi.dots-vertical',), {'color': self.MAIN_FG_COLOR}],
            'arrow_debugger':          [('mdi.arrow-right-bold',), {'color': SpyderPalette.ICON_2, 'scale_factor': 1.5}],
            'arrow-step-over':         [('mdi.debug-step-over',), {'color': SpyderPalette.ICON_2}],
            'arrow-continue':          [('mdi.fast-forward',), {'color': SpyderPalette.ICON_2}],
            'arrow-step-in':           [('mdi.debug-step-into',), {'color': SpyderPalette.ICON_2}],
            'arrow-step-out':          [('mdi.debug-step-out',), {'color': SpyderPalette.ICON_2}],
            'stop_debug':              [('mdi.stop',), {'color': SpyderPalette.ICON_2}],
            'run':                     [('mdi.play',), {'color': SpyderPalette.ICON_3}],
            'todo_list':               [('mdi.check-bold',), {'color': self.MAIN_FG_COLOR}],
            'wng_list':                [('mdi.alert',), {'options': [{'color': SpyderPalette.COLOR_WARN_2, 'color_disabled': SpyderPalette.COLOR_TEXT_4}]}],
            'prev_wng':                [('mdi.arrow-left',), {'options': [{'color': SpyderPalette.ICON_1, 'color_disabled': SpyderPalette.COLOR_TEXT_4}]}],
            'next_wng':                [('mdi.arrow-right',), {'options': [{'color': SpyderPalette.ICON_1, 'color_disabled': SpyderPalette.COLOR_TEXT_4}]}],
            'prev_cursor':             [('mdi.hand-pointing-left',), {'color': self.MAIN_FG_COLOR}],
            'next_cursor':             [('mdi.hand-pointing-right',), {'color': self.MAIN_FG_COLOR}],
            'comment':                 [('mdi.comment-text-outline',), {'color': self.MAIN_FG_COLOR}],
            'indent':                  [('mdi.format-indent-increase',), {'color': self.MAIN_FG_COLOR}],
            'unindent':                [('mdi.format-indent-decrease',), {'color': self.MAIN_FG_COLOR}],
            'toggle_lowercase':        [('mdi.format-letter-case-lower',), {'color': self.MAIN_FG_COLOR}],
            'toggle_uppercase':        [('mdi.format-letter-case-upper',), {'color': self.MAIN_FG_COLOR}],
            'gotoline':                [('mdi.format-line-spacing',), {'color': self.MAIN_FG_COLOR}],
            'error':                   [('mdi.close-circle',), {'color': SpyderPalette.COLOR_ERROR_1}],
            'warning':                 [('mdi.alert',), {'color': SpyderPalette.COLOR_WARN_2}],
            'information':             [('mdi.information-outline',), {'color': SpyderPalette.GROUP_9}],
            'hint':                    [('mdi.lightbulb',), {'color': SpyderPalette.GROUP_9}],
            'todo':                    [('mdi.check-bold',), {'color': SpyderPalette.GROUP_9}],
            'ipython_console':         [('mdi.console',), {'color': self.MAIN_FG_COLOR}],
            'python':                  [('spyder.python-logo-up', 'spyder.python-logo-down'), {'options': [{'color': SpyderPalette.PYTHON_LOGO_UP}, {'color': SpyderPalette.PYTHON_LOGO_DOWN}]}],
            'pythonpath':              [('spyder.python-logo-up', 'spyder.python-logo-down'), {'options': [{'color': SpyderPalette.PYTHON_LOGO_UP}, {'color': SpyderPalette.PYTHON_LOGO_DOWN}]}],
            'findf':                   [('mdi.file-find-outline',), {'color': self.MAIN_FG_COLOR}],
            'history':                 [('mdi.history',), {'color': self.MAIN_FG_COLOR}],
            'files':                   [('mdi.file-multiple',), {'color': self.MAIN_FG_COLOR}],
            'question_tip':            [('mdi.help-circle-outline',), {'color': SpyderPalette.COLOR_BACKGROUND_6}],
            'question_tip_hover':      [('mdi.help-circle-outline',), {'color': SpyderPalette.COLOR_TEXT_4}],
            'info_tip':                [('mdi.information-outline',), {'color': SpyderPalette.COLOR_BACKGROUND_6}],
            'info_tip_hover':          [('mdi.information-outline',), {'color': SpyderPalette.COLOR_TEXT_4}],
            'help':                    [('mdi.help-circle',), {'color': self.MAIN_FG_COLOR}],
            'online_help':             [('mdi.help-rhombus-outline',), {'color': self.MAIN_FG_COLOR}],
            'lock':                    [('mdi.lock',), {'color': self.MAIN_FG_COLOR}],
            'lock_open':               [('mdi.lock-open',), {'color': self.MAIN_FG_COLOR}],
            'outline_explorer':        [('mdi.file-tree',), {'color': self.MAIN_FG_COLOR}],
            'switcher':                [('mdi.arrow-left-right-bold',), {'color': self.MAIN_FG_COLOR}],
            'variable_explorer':       [('mdi.telescope',), {'color': self.MAIN_FG_COLOR}],
            'dictedit':                [('mdi.view-list-outline',), {'color': self.MAIN_FG_COLOR}],
            'previous':                [('mdi.arrow-left-bold',), {'color': self.MAIN_FG_COLOR}],
            'next':                    [('mdi.arrow-right-bold',), {'color': self.MAIN_FG_COLOR}],
            'up':                      [('mdi.arrow-up-bold',), {'color': self.MAIN_FG_COLOR}],
            'spyder':                  [('spyder.spyder-logo-background', 'spyder.spyder-logo-web', 'spyder.spyder-logo-snake'),  {'options': [{'color': SpyderPalette.SPYDER_LOGO_BACKGROUND}, {'color': SpyderPalette.SPYDER_LOGO_WEB}, {'color': SpyderPalette.SPYDER_LOGO_SNAKE}]}],
            'find':                    [('mdi.magnify',), {'color': self.MAIN_FG_COLOR}],
            'replace':                 [('mdi.find-replace',), {'color': self.MAIN_FG_COLOR}],
            'number_matches':          [('mdi.pound-box-outline',), {'color': self.MAIN_FG_COLOR}],
            'undo':                    [('mdi.undo',), {'color': self.MAIN_FG_COLOR}],
            'redo':                    [('mdi.redo',), {'color': self.MAIN_FG_COLOR}],
            'refresh':                 [('mdi.refresh',), {'color': self.MAIN_FG_COLOR}],
            'restart':                 [('mdi.reload',), {'color': self.MAIN_FG_COLOR}],
            'editcopy':                [('mdi.content-copy',), {'color': self.MAIN_FG_COLOR}],
            'editcut':                 [('mdi.content-cut',), {'color': self.MAIN_FG_COLOR}],
            'editclear':               [('mdi.delete',), {'color': self.MAIN_FG_COLOR}],
            'selectall':               [('mdi.select-all',), {'color': self.MAIN_FG_COLOR}],
            'exit':                    [('mdi.power',), {'color': self.MAIN_FG_COLOR}],
            'advanced':                [('mdi.package-variant',), {'color': self.MAIN_FG_COLOR}],
            'bug':                     [('mdi.bug',), {'color': self.MAIN_FG_COLOR}],
            'window_nofullscreen':     [('mdi.arrow-collapse-all',), {'color': self.MAIN_FG_COLOR}],
            'window_fullscreen':       [('mdi.arrow-expand-all',), {'color': self.MAIN_FG_COLOR}],
            'MessageBoxWarning':       [('mdi.alert',), {'color': self.MAIN_FG_COLOR}],
            'arredit':                 [('mdi.table-edit',), {'color': self.MAIN_FG_COLOR}],
            'home':                    [('mdi.home',), {'color': self.MAIN_FG_COLOR}],
            'show':                    [('mdi.eye',), {'color': self.MAIN_FG_COLOR}],
            'plot':                    [('mdi.chart-bar',), {'color': self.MAIN_FG_COLOR}],
            'plot.fit_to_pane':        [('mdi6.fit-to-screen',), {'color': self.MAIN_FG_COLOR}],
            'hist':                    [('mdi.chart-histogram',), {'color': self.MAIN_FG_COLOR}],
            'imshow':                  [('mdi.image',), {'color': self.MAIN_FG_COLOR}],
            'insert':                  [('mdi.login',), {'color': self.MAIN_FG_COLOR}],
            'insert_above':            [('mdi.table-arrow-up',), {'color': self.MAIN_FG_COLOR}],
            'insert_below':            [('mdi.table-arrow-down',), {'color': self.MAIN_FG_COLOR}],
            'insert_after':            [('mdi.table-arrow-right',), {'color': self.MAIN_FG_COLOR}],
            'insert_before':           [('mdi.table-arrow-left',), {'color': self.MAIN_FG_COLOR}],
            'rename':                  [('mdi.rename-box',), {'color': self.MAIN_FG_COLOR}],
            'move':                    [('mdi.file-move',), {'color': self.MAIN_FG_COLOR}],
            'edit_add':                [('mdi.plus-box',), {'color': self.MAIN_FG_COLOR}],
            'select_row':              [('mdi.plus-box-outline',), {'color': self.MAIN_FG_COLOR}],
            'deselect_row':            [('mdi.minus-box-outline',), {'color': self.MAIN_FG_COLOR}],
            'duplicate_row':           [('ph.rows',), {'color': self.MAIN_FG_COLOR}],
            'duplicate_column':        [('ph.columns',), {'color': self.MAIN_FG_COLOR}],
            'collapse_column':         [('mdi.arrow-collapse-horizontal',), {'color': self.MAIN_FG_COLOR}],
            'collapse_row':            [('mdi.arrow-collapse-vertical',), {'color': self.MAIN_FG_COLOR}],
            'delete_row':              [('mdi.table-row-remove',), {'color': self.MAIN_FG_COLOR}],
            'delete_column':           [('mdi.table-column-remove',), {'color': self.MAIN_FG_COLOR}],
            # Although this icon is not used in Spyder, it can be in other plugins
            # because it's the opposite of edit_add. So, don't remove it.
            'edit_remove':             [('mdi.minus-box',), {'color': self.MAIN_FG_COLOR}],
            'format_float':            [('mdi.decimal-increase',), {'color': self.MAIN_FG_COLOR}],
            'background_color':        [('mdi.format-color-fill',), {'color': self.MAIN_FG_COLOR}],
            'browse_tab':              [('mdi.tab',), {'color': self.MAIN_FG_COLOR}],
            'filelist':                [('mdi.view-list',), {'color': self.MAIN_FG_COLOR}],
            'newwindow':               [('mdi.window-maximize',), {'color': self.MAIN_FG_COLOR}],
            'close_panel':             [('mdi.close-box-outline',), {'color': self.MAIN_FG_COLOR}],
            'fromcursor':              [('mdi.cursor-pointer',), {'color': self.MAIN_FG_COLOR, 'rotated': 90}],
            'filter':                  [('mdi.filter',), {'color': self.MAIN_FG_COLOR}],
            'folder_new':              [('mdi.folder-plus',), {'color': self.MAIN_FG_COLOR}],
            'vcs_commit':              [('mdi.source-commit',), {'color': SpyderPalette.ICON_3}],
            'vcs_browse':              [('mdi.source-repository',), {'color': SpyderPalette.ICON_3}],
            'fileimport':              [('mdi.download',), {'color': self.MAIN_FG_COLOR}],
            'fileexport':              [('mdi.upload',), {'color': self.MAIN_FG_COLOR}],
            'options_less':            [('mdi.minus-box',), {'color': self.MAIN_FG_COLOR}],
            'options_more':            [('mdi.plus-box',), {'color': self.MAIN_FG_COLOR}],
            'ArrowDown':               [('mdi.arrow-down-bold-circle',), {'color': self.MAIN_FG_COLOR}],
            'ArrowUp':                 [('mdi.arrow-up-bold-circle',), {'color': self.MAIN_FG_COLOR}],
            'ArrowBack':               [('mdi.arrow-left-bold-circle',), {'color': self.MAIN_FG_COLOR}],
            'ArrowForward':            [('mdi.arrow-right-bold-circle',), {'color': self.MAIN_FG_COLOR}],
            'DialogApplyButton':       [('mdi.check',), {'color': self.MAIN_FG_COLOR}],
            'DialogCloseButton':       [('mdi.close',), {'color': self.MAIN_FG_COLOR}],
            'DirClosedIcon':           [('mdi.folder',), {'color': self.MAIN_FG_COLOR}],
            'DialogHelpButton':        [('mdi.lifebuoy',), {'color': self.MAIN_FG_COLOR}],
            'VideoIcon':               [('mdi.video',), {'color': self.MAIN_FG_COLOR}],
            'MessageBoxInformation':   [('mdi.information-outline',), {'color': self.MAIN_FG_COLOR}],
            'DirOpenIcon':             [('mdi.folder-open',), {'color': self.MAIN_FG_COLOR}],
            'FileIcon':                [('mdi.file',), {'color': self.MAIN_FG_COLOR}],
            'GenericFileIcon':         [('mdi.file-outline',), {'color': self.MAIN_FG_COLOR}],
            'ExcelFileIcon':           [('mdi.file-excel',), {'color': self.MAIN_FG_COLOR}],
            'WordFileIcon':            [('mdi.file-word',), {'color': self.MAIN_FG_COLOR}],
            'PowerpointFileIcon':      [('mdi.file-powerpoint',), {'color': self.MAIN_FG_COLOR}],
            'PDFIcon':                 [('mdi.file-pdf',), {'color': self.MAIN_FG_COLOR}],
            'AudioFileIcon':           [('mdi.file-music',), {'color': self.MAIN_FG_COLOR}],
            'ImageFileIcon':           [('mdi.file-image',), {'color': self.MAIN_FG_COLOR}],
            'VideoFileIcon':           [('mdi.file-video',), {'color': self.MAIN_FG_COLOR}],
            'TextFileIcon':            [('mdi.file-document',), {'color': self.MAIN_FG_COLOR}],
            'CFileIcon':               [('mdi.language-c',), {'color': self.MAIN_FG_COLOR}],
            'CppFileIcon':             [('mdi.language-cpp',), {'color': self.MAIN_FG_COLOR}],
            'CsharpFileIcon':          [('mdi.language-csharp',), {'color': self.MAIN_FG_COLOR}],
            'PythonFileIcon':          [('mdi.language-python',), {'color': self.MAIN_FG_COLOR}],
            'JavaFileIcon':            [('mdi.language-java',), {'color': self.MAIN_FG_COLOR}],
            'JavascriptFileIcon':      [('mdi.language-javascript',), {'color': self.MAIN_FG_COLOR}],
            'RFileIcon':               [('mdi.language-r',), {'color': self.MAIN_FG_COLOR}],
            'SwiftFileIcon':           [('mdi.language-swift',), {'color': self.MAIN_FG_COLOR}],
            'GridFileIcon':            [('mdi.grid',), {'color': self.MAIN_FG_COLOR}],
            'WindowsFileIcon':         [('mdi.windows',), {'color': self.MAIN_FG_COLOR}],
            'PowershellFileIcon':      [('mdi.powershell',), {'color': self.MAIN_FG_COLOR}],
            'DollarFileIcon':          [('mdi.currency-usd',), {'color': self.MAIN_FG_COLOR}],
            'MarkdownFileIcon':        [('mdi.markdown',), {'color': self.MAIN_FG_COLOR}],
            'JsonFileIcon':            [('mdi.json',), {'color': self.MAIN_FG_COLOR}],
            'ExclamationFileIcon':     [('mdi.exclamation',), {'color': self.MAIN_FG_COLOR}],
            'CodeFileIcon':            [('mdi.xml',), {'color': self.MAIN_FG_COLOR}],
            'arrow':                   [('mdi.arrow-right-bold',), {'color': self.MAIN_FG_COLOR}],
            'collapse':                [('mdi.collapse-all',), {'color': self.MAIN_FG_COLOR}],
            'expand':                  [('mdi.expand-all',), {'color': self.MAIN_FG_COLOR}],
            'restore':                 [('mdi.subdirectory-arrow-right',), {'color': self.MAIN_FG_COLOR, 'rotated': 270}],
            'collapse_selection':      [('mdi.minus-box',), {'color': self.MAIN_FG_COLOR}],
            'expand_selection':        [('mdi.plus-box',), {'color': self.MAIN_FG_COLOR}],
            'copywop':                 [('mdi.console-line',), {'color': self.MAIN_FG_COLOR}],
            'editpaste':               [('mdi.content-paste',), {'color': self.MAIN_FG_COLOR}],
            'edit':                    [('mdi.pencil',), {'color': self.MAIN_FG_COLOR}],
            'convention':              [('mdi.alpha-c-circle',), {'color': SpyderPalette.ICON_2, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'refactor':                [('mdi.alpha-r-circle',), {'color': SpyderPalette.ICON_2, 'scale_factor': self.BIG_ATTR_FACTOR}],
            '2uparrow':                [('mdi.arrow-collapse-up',), {'color': self.MAIN_FG_COLOR}],
            '1uparrow':                [('mdi.arrow-up',), {'color': self.MAIN_FG_COLOR}],
            '2downarrow':              [('mdi.arrow-collapse-down',), {'color': self.MAIN_FG_COLOR}],
            '1downarrow':              [('mdi.arrow-down',), {'color': self.MAIN_FG_COLOR}],
            'prepend':                 [('mdi.arrow-collapse-left',), {'color': self.MAIN_FG_COLOR}],
            'append':                  [('mdi.arrow-collapse-right',), {'color': self.MAIN_FG_COLOR}],
            'undock':                  [('mdi.open-in-new',), {'color': self.MAIN_FG_COLOR}],
            'close_pane':              [('mdi.window-close',), {'color': self.MAIN_FG_COLOR}],
            'toolbar_ext_button':      [('mdi.dots-horizontal',), {'color': self.MAIN_FG_COLOR}],
            'inapp_appeal':            [('mdi6.heart',), {'color': SpyderPalette.COLOR_HEART}],
            'update':                  [('mdi6.tray-arrow-down',), {'color': self.MAIN_FG_COLOR}],
            # --- Autocompletion/document symbol type icons --------------
            'completions':             [('mdi.code-tags-check',), {'color': self.MAIN_FG_COLOR}],
            'keyword':                 [('mdi.alpha-k-box',), {'color': SpyderPalette.GROUP_9, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'color':                   [('mdi.alpha-c-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'enum':                    [('mdi.alpha-e-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'value':                   [('mdi.alpha-v-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'constant':                [('mdi.alpha-c-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'unit':                    [('mdi.alpha-u-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'text':                    [('mdi.alphabetical-variant',), {'color': self.MAIN_FG_COLOR, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'file':                    [('mdi.file',), {'color': self.MAIN_FG_COLOR, 'scale_factor': self.SMALL_ATTR_FACTOR}],
            'snippet':                 [('mdi.alpha-s-box',), {'color': SpyderPalette.GROUP_11, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'attribute':               [('mdi.alpha-a-box',), {'color': SpyderPalette.GROUP_12, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'reference':               [('mdi.alpha-r-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'variable':                [('mdi.alpha-v-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'field':                   [('mdi.alpha-a-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'property':                [('mdi.alpha-p-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'module':                  [('mdi.alpha-m-box',), {'color': SpyderPalette.GROUP_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'namespace':               [('mdi.alpha-n-box',), {'color': SpyderPalette.GROUP_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'package':                 [('mdi.alpha-p-box',), {'color': SpyderPalette.GROUP_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'class':                   [('mdi.alpha-c-box',), {'color': SpyderPalette.ICON_2, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'interface':               [('mdi.alpha-i-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'string':                  [('mdi.alpha-s-box',), {'color': SpyderPalette.GROUP_9, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'number':                  [('mdi.alpha-n-box',), {'color': SpyderPalette.GROUP_9, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'boolean':                 [('mdi.alpha-b-box',), {'color': SpyderPalette.GROUP_12, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'array':                   [('mdi.alpha-a-box',), {'color': SpyderPalette.GROUP_9, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'object':                  [('mdi.alpha-o-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'key':                     [('mdi.alpha-k-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'null':                    [('mdi.alpha-n-box',), {'color': SpyderPalette.GROUP_12, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'enum_member':             [('mdi.alpha-e-box',), {'color': SpyderPalette.COLOR_ERROR_3, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'struct':                  [('mdi.alpha-s-box',), {'color': SpyderPalette.ICON_2, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'event':                   [('mdi.alpha-e-box',), {'color': SpyderPalette.COLOR_WARN_3, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'operator':                [('mdi.alpha-o-box',), {'color': SpyderPalette.COLOR_WARN_3, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'type_parameter':          [('mdi.alpha-t-box',), {'color': SpyderPalette.COLOR_WARN_3, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'private2':                [('mdi.eye-off',), {'color': SpyderPalette.COLOR_ERROR_3, 'scale_factor': self.SMALL_ATTR_FACTOR}],
            'private1':                [('mdi.eye-off',), {'color': SpyderPalette.COLOR_ERROR_3, 'scale_factor': self.SMALL_ATTR_FACTOR}],
            'method':                  [('mdi.alpha-m-box',), {'color': SpyderPalette.ICON_3, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'constructor':             [('mdi.alpha-c-box',), {'color': SpyderPalette.ICON_5, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'function':                [('mdi.alpha-f-box',), {'color': SpyderPalette.COLOR_WARN_3, 'scale_factor': self.BIG_ATTR_FACTOR}],
            'blockcomment':            [('mdi.pound',), {'color': SpyderPalette.ICON_2, 'scale_factor': self.SMALL_ATTR_FACTOR}],
            'cell':                    [('mdi.percent',), {'color':SpyderPalette.GROUP_9, 'scale_factor': self.SMALL_ATTR_FACTOR}],
            'no_match':                [('mdi.checkbox-blank-circle',), {'color': SpyderPalette.GROUP_3, 'scale_factor': self.SMALL_ATTR_FACTOR}],
            'github':                  [('mdi.github',), {'color': self.MAIN_FG_COLOR}],
            # --- Spyder Tour --------------------------------------------------------
            'tour':                    [('mdi.compass',), {'color': self.MAIN_FG_COLOR}],
            'tour.close':              [('mdi.close',), {'color': self.MAIN_FG_COLOR}],
            'tour.home':               [('mdi.skip-backward',), {'color': self.MAIN_FG_COLOR}],
            'tour.previous':           [('mdi.skip-previous',), {'color': self.MAIN_FG_COLOR}],
            'tour.next':               [('mdi.skip-next',), {'color': self.MAIN_FG_COLOR}],
            'tour.end':                [('mdi.skip-forward',), {'color': self.MAIN_FG_COLOR}],
            # --- Profiler ------------------------------------------------
            'hide':                    [('mdi.eye-off',), {'color': self.MAIN_FG_COLOR}],
            'slow':                    [('mdi.speedometer-slow',), {'color': self.MAIN_FG_COLOR}],
            'stop_profile':            [('mdi.stop',), {'color': SpyderPalette.ICON_7}],
            'callers_or_callees':      [('mdi6.call-made', 'mdi6.call-received'), {'options': [{'color': self.MAIN_FG_COLOR, 'offset': (-0.2, -0.2)}, {'color': self.MAIN_FG_COLOR, 'offset': (0.2, 0.2)}]}],
            'callers':                 [('mdi6.call-received',), {'color': self.MAIN_FG_COLOR}],
            'callees':                 [('mdi6.call-made',), {'color': self.MAIN_FG_COLOR}],
            # --- Other ------------------------------------------------
            'spyder.example':          [('mdi.eye',), {'color': self.MAIN_FG_COLOR}],
            'spyder.line_profiler':    [('mdi.eye',), {'color': self.MAIN_FG_COLOR}],
            'symbol_find':             [('mdi.at',), {'color': self.MAIN_FG_COLOR}],
            'folding.arrow_right':     [('mdi.chevron-right',), {'color': self.MAIN_FG_COLOR}],
            'folding.arrow_down':      [('mdi.chevron-down',), {'color': self.MAIN_FG_COLOR}],
            'lspserver.down':          [('mdi.alert',), {'color': self.MAIN_FG_COLOR}],
            'lspserver.ready':         [('mdi.check',), {'color': self.MAIN_FG_COLOR}],
            'dependency_ok':           [('mdi.check',), {'color': SpyderPalette.COLOR_SUCCESS_2}],
            'dependency_warning':      [('mdi.alert',), {'color': SpyderPalette.COLOR_WARN_2}],
            'dependency_error':        [('mdi.alert',), {'color': SpyderPalette.COLOR_ERROR_1}],
            'broken_image':            [('mdi.image-broken-variant',), {'color': self.MAIN_FG_COLOR}],
            # --- Status bar --------------------------------------------------------
            'code_fork':               [('mdi.source-fork',), {'color': self.MAIN_FG_COLOR}],
            'statusbar':               [('mdi.dock-bottom',), {'color': self.MAIN_FG_COLOR}],
            # --- Plugin registry ---------------------------------------------------
            'plugins':                 [('mdi.puzzle',), {'color': self.MAIN_FG_COLOR}],
            # --- Print preview dialog ----------------------------------------------
            'print.fit_width':         [('mdi.arrow-expand-horizontal',), {'color': self.MAIN_FG_COLOR}],
            'print.fit_page':          [('mdi.stretch-to-page-outline',), {'color': self.MAIN_FG_COLOR}],
            'portrait':                [('mdi.crop-portrait',), {'color': self.MAIN_FG_COLOR}],
            'landscape':               [('mdi.crop-landscape',), {'color': self.MAIN_FG_COLOR}],
            'previous_page':           [('mdi.chevron-left',), {'color': self.MAIN_FG_COLOR}],
            'next_page':               [('mdi.chevron-right',), {'color': self.MAIN_FG_COLOR}],
            'first_page':              [('mdi.page-first',), {'color': self.MAIN_FG_COLOR}],
            'last_page':               [('mdi.page-last',), {'color': self.MAIN_FG_COLOR}],
            'print.single_page':       [('mdi.file-document-outline',), {'color': self.MAIN_FG_COLOR}],
            'print.all_pages':         [('mdi.file-document-multiple-outline',), {'color': self.MAIN_FG_COLOR}],
            'print.page_setup':        [('mdi.ruler-square',), {'color': self.MAIN_FG_COLOR}],
            # --- Remote connections ----------------------------------------------
            'add_server':              [('mdi.server-plus',), {'color': self.MAIN_FG_COLOR}],
            'remote_server':           [('mdi.server-network',), {'color': self.MAIN_FG_COLOR}],
            # --- For our collapsed widget
            'collapsed':               [('mdi.chevron-right',), {'color': self.MAIN_FG_COLOR, 'scale_factor': 1.3}],
            'expanded':                [('mdi.chevron-down',), {'color': self.MAIN_FG_COLOR, 'scale_factor': 1.3}],
        }

    def get_std_icon(self, name, size=None):
        """Get standard platform icon."""
        if not name.startswith('SP_'):
            name = 'SP_' + name
        icon = QWidget().style().standardIcon(getattr(QStyle, name))
        if size is None:
            return icon
        else:
            return QIcon(icon.pixmap(size, size))

    def get_icon(self, name, resample=False):
        """Return image inside a QIcon object.

        Parameters
        ----------
        name: str
            Image name or icon
        resample: bool
            If True, manually resample icon pixmaps for usual sizes
            (16, 24, 32, 48, 96, 128, 256). This is recommended for
            QMainWindow icons created from SVG images on non-Windows
            platforms due to a Qt bug. See spyder-ide/spyder#1314.

        Returns
        -------
        QIcon
            Icon object with the requested image.

        Notes
        -----
        For SVG files, this method will automatically apply theme-based
        colorization if the SVG contains elements with semantic class names
        like 'ICON_1', 'ICON_2', 'ICON_3', etc. These classes
        correspond to color definitions in SpyderPalette.

        This allows icons to automatically adapt to the current theme's
        color scheme, supporting both dark and light themes as well as
        custom user themes.
        """
        # Check cache first
        cache_key = f"{name}_{resample}"
        if cache_key in self._icon_cache:
            return self._icon_cache[cache_key]

        # Get the icon's file path
        icon_path = get_image_path(name)

        # Process the icon
        if icon_path.endswith('.svg'):
            icon = self._process_svg_icon(icon_path, resample)
        else:
            icon = self._process_regular_icon(icon_path, resample)

        # Cache the result
        self._icon_cache[cache_key] = icon
        return icon

    def _process_svg_icon(self, icon_path, resample):
        """
        Process an SVG icon with proper colorization for multi-color icons.

        This method handles SVG icons with multiple colored paths, each defined
        by a class attribute that maps to a color in ICON_COLORS. It supports
        high DPI displays by generating icons at multiple resolutions.

        Parameters
        ----------
        icon_path : str
            Path to the SVG icon file
        resample : bool
            Whether to resample the icon for various sizes

        Returns
        -------
        QIcon
            A properly colored icon with support for normal, disabled and
            selected states
        """
        try:
            # Use SVGColorize to extract paths with their associated colors
            svg_paths_data = SVGColorize.get_colored_paths(
                icon_path, self.ICON_COLORS
            )
            if not svg_paths_data:
                return self._process_regular_icon(icon_path, resample)

            # Define standard icon sizes for high DPI support
            sizes = [16, 24, 32, 48, 96, 128, 256, 512]
            icon = QIcon()

            # Extract SVG metadata
            width = svg_paths_data.get('width', 24)
            height = svg_paths_data.get('height', 24)
            viewbox = svg_paths_data.get('viewbox')
            paths = svg_paths_data.get('paths', [])

            # Process each size to ensure proper scaling on all displays
            for size in sizes:
                # Create the base pixmap for this size using SVGColorize
                svg_colorizer = SVGColorize(icon_path)
                pixmap = svg_colorizer.render_colored_svg(
                    paths, size, width, height, viewbox
                )

                # Add pixmap for normal state
                icon.addPixmap(pixmap, QIcon.Normal)

                # Create disabled version (grayed out)
                disabled_pixmap = self._create_disabled_pixmap(pixmap)
                icon.addPixmap(disabled_pixmap, QIcon.Disabled)

                # Use normal state for selected state as well
                icon.addPixmap(pixmap, QIcon.Selected)

            return icon
        except Exception:
            # Any error, fall back to regular processing
            return self._process_regular_icon(icon_path, resample)

    def _create_disabled_pixmap(self, source_pixmap):
        """
        Create a disabled (grayed out) version of a pixmap.

        Parameters
        ----------
        source_pixmap : QPixmap
            Source pixmap to create disabled version from

        Returns
        -------
        QPixmap
            Disabled version of the pixmap
        """
        disabled_pixmap = QPixmap(source_pixmap.size())
        disabled_pixmap.fill(QColor(0, 0, 0, 0))  # Transparent
        
        # Draw the source pixmap first
        disabled_painter = QPainter(disabled_pixmap)
        disabled_painter.drawPixmap(0, 0, source_pixmap)
        
        # Apply disabled color overlay
        disabled_painter.setCompositionMode(QPainter.CompositionMode_SourceIn)
        disabled_painter.fillRect(
            disabled_pixmap.rect(), QColor(SpyderPalette.COLOR_DISABLED)
        )
        disabled_painter.end()
        
        return disabled_pixmap

    def _process_regular_icon(self, icon_path, resample):
        """Process a regular (non-SVG) icon."""
        # This is used to wrap the image into a QIcon container so we can get
        # pixmaps for it.
        wrapping_icon = QIcon(icon_path)

        # This is the icon object that will be returned by this method.
        icon = QIcon()

        if resample:
            # This only applies to the Spyder 2 icons
            for size in (16, 24, 32, 48, 96, 128, 256, 512):
                icon.addPixmap(wrapping_icon.pixmap(size, size))
            return icon
        else:
            # These are the necessary adjustments for our SVG icons.

            # -- Normal state
            # NOTE: We take pixmaps as large as the ones below to not have
            # pixelated icons on high dpi screens.
            # Fixes spyder-ide/spyder#19520
            normal_state = wrapping_icon.pixmap(512, 512)
            icon.addPixmap(normal_state, QIcon.Normal)

            # -- Disabled state
            # Taken from https://stackoverflow.com/a/65618075/438386
            disabled_color = QColor(SpyderPalette.COLOR_DISABLED)
            disabled_state = wrapping_icon.pixmap(512, 512)
            qp = QPainter(disabled_state)
            qp.setCompositionMode(QPainter.CompositionMode_SourceIn)
            qp.fillRect(disabled_state.rect(), disabled_color)
            qp.end()
            icon.addPixmap(disabled_state, QIcon.Disabled)

            # -- Selected state
            # We use the normal state pixmap for the selected state as well.
            icon.addPixmap(normal_state, QIcon.Selected)

            return icon

    def icon(self, name, scale_factor=None, resample=False):
        theme = CONF.get('appearance', 'icon_theme')
        if theme == 'spyder 3':
            try:
                # Try to load the icons from QtAwesome
                if not self._resource['loaded']:
                    qta.load_font('spyder', 'spyder.ttf', 'spyder-charmap.json',
                                directory=self._resource['directory'])
                    self._resource['loaded'] = True
                args, kwargs = self._qtaargs[name]
                if scale_factor is not None:
                    kwargs['scale_factor'] = scale_factor
                kwargs['color_disabled'] = SpyderPalette.COLOR_DISABLED
                return qta.icon(*args, **kwargs)
            except KeyError:
                # Load custom icons
                icon = QIcon(self.get_icon(name))
                return icon if icon is not None else QIcon()

    def get_icon_by_extension_or_type(self, fname, scale_factor):
        """Return the icon depending on the file extension"""
        application_icons = {}
        application_icons.update(self.BIN_FILES)
        application_icons.update(self.DOCUMENT_FILES)

        basename = osp.basename(fname)
        __, extension = osp.splitext(basename.lower())

        # Catch error when it's not possible to access the Windows registry to
        # check for this.
        # Fixes spyder-ide/spyder#21304
        try:
            mime_type, __ = mime.guess_type(basename)
        except PermissionError:
            mime_type = None

        if osp.isdir(fname):
            extension = "Folder"

        if (extension, scale_factor) in self.ICONS_BY_EXTENSION:
            return self.ICONS_BY_EXTENSION[(extension, scale_factor)]

        if osp.isdir(fname):
            icon_by_extension = self.icon('DirClosedIcon', scale_factor)
        else:
            icon_by_extension = self.icon('GenericFileIcon')

            if extension in self.OFFICE_FILES:
                icon_by_extension = self.icon(
                    self.OFFICE_FILES[extension], scale_factor)
            elif extension in self.LANGUAGE_ICONS:
                icon_by_extension = self.icon(
                    self.LANGUAGE_ICONS[extension], scale_factor)
            else:
                if extension == '.ipynb':
                    icon_by_extension = self.icon('notebook')
                elif extension == '.tex':
                    icon_by_extension = self.icon('file_type_tex')
                elif extension in EDIT_EXTENSIONS:
                    icon_by_extension = self.icon('TextFileIcon', scale_factor)
                elif mime_type is not None:
                    try:
                        # Fix for spyder-ide/spyder#5080. Even though
                        # mimetypes.guess_type documentation states that
                        # the return value will be None or a tuple of
                        # the form type/subtype, in the Windows registry,
                        # .sql has a mimetype of text\plain
                        # instead of text/plain therefore mimetypes is
                        # returning it incorrectly.
                        file_type, bin_name = mime_type.split('/')
                    except ValueError:
                        file_type = None
                    if file_type is None:
                        icon_by_extension = self.icon('binary')
                    elif file_type == 'audio':
                        icon_by_extension = self.icon(
                            'AudioFileIcon', scale_factor)
                    elif file_type == 'video':
                        icon_by_extension = self.icon(
                            'VideoFileIcon', scale_factor)
                    elif file_type == 'image':
                        icon_by_extension = self.icon(
                            'ImageFileIcon', scale_factor)
                    elif file_type == 'application':
                        if bin_name in application_icons:
                            icon_by_extension = self.icon(
                                application_icons[bin_name], scale_factor)

        self.ICONS_BY_EXTENSION[(extension, scale_factor)] = icon_by_extension
        return icon_by_extension

    def base64_from_icon(self, icon_name, width, height):
        """Convert icon to base64 encoding."""
        icon_obj = self.icon(icon_name)
        return base64_from_icon_obj(icon_obj, width, height)

    def base64_from_icon_obj(self, icon_obj, width, height):
        """Convert icon object to base64 encoding."""
        image = QImage(icon_obj.pixmap(width, height).toImage())
        byte_array = QByteArray()
        buffer = QBuffer(byte_array)
        image.save(buffer, "PNG")
        return byte_array.toBase64().data().decode()


ima = IconManager()


# -----------------------------------------------------------------------------
# TODO: Remove the following code once external plugins have been updated to
# the new icon manager.
# -----------------------------------------------------------------------------
def get_std_icon(name, size=None):
    return ima.get_std_icon(name, size=size)


def get_icon(name, resample=False):
    return ima.get_icon(name, resample=resample)


def icon(name, scale_factor=None, resample=False):
    return ima.icon(name, scale_factor=scale_factor, resample=resample)


def get_icon_by_extension_or_type(fname, scale_factor):
    return ima.get_icon_by_extension_or_type(fname, scale_factor)


def base64_from_icon(icon_name, width, height):
    return ima.base64_from_icon(icon_name, width, height)


def base64_from_icon_obj(icon_obj, width, height):
    return ima.base64_from_icon_obj(icon_obj, width, height)


MAIN_FG_COLOR = ima.MAIN_FG_COLOR
